package com.abc.xxx.config.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.Date;
import java.util.Map;

@Slf4j
public class JwtService {

    public String jwtSecret = "secret";

    public long jwtExpire = 1800;

    public long jwtAutoRefreshInAdvance = 900;

    public JwtService(String jwtSecret, long jwtExpire, long jwtAutoRefreshInAdvance) {
        this.jwtSecret = jwtSecret;
        this.jwtExpire = jwtExpire;
        this.jwtAutoRefreshInAdvance = jwtAutoRefreshInAdvance;
    }

    /**
     * 创建token
     *
     * @param subject 主体，即登录用户名
     * @param role    用户拥有的角色
     * @return
     */
    public String createToken(String subject, String role) {

        Date now = new Date();
        Date expiration = new Date(now.getTime() + jwtExpire * 1000);

        Claims playload = Jwts.claims();
        playload.put("role", role);
        SecretKey key = Keys.hmacShaKeyFor(jwtSecret.getBytes());
        //Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        return Jwts.builder()
                .setIssuer("admin-server") // 签发人
                .setExpiration(expiration) // 过期时间
                .setSubject(subject)       // 主体
                .setNotBefore(now)         // 生效时间
                .setIssuedAt(now)          // 签发时间
                .addClaims(playload)       // 载荷
                .signWith(key)
                //.signWith(SignatureAlgorithm.HS256, jwtSecret)
                .compact();
    }

    /**
     * 创建token
     *
     * @param subject 主体，即登录用户名
     * @param data    jwt携带的数据
     * @return
     */
    public String createToken(String subject, Map<String,Object> data) {

        Date now = new Date();
        Date expiration = new Date(now.getTime() + jwtExpire * 1000);
        log.info("data: {}",data);
        Claims playload = Jwts.claims();
        playload.putAll(data);
        //Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        SecretKey key = Keys.hmacShaKeyFor(jwtSecret.getBytes());
        return Jwts.builder()
                .setIssuer("tenant-server") // 签发人
                .setExpiration(expiration)  // 过期时间
                .setSubject(subject)        // 主体
                .setNotBefore(now)          // 生效时间
                .setIssuedAt(now)           // 签发时间
                .addClaims(playload)        // 载荷
                .signWith(key)
                .compact();
    }

    /**
     * 从请求中解析出jwt token
     *
     * @param req 请求
     * @return
     */
    public String resolveToken(HttpServletRequest req) {
        String bearerToken = req.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    /**
     * 解析出jwt token的body，如果抛出ExpiredJwtException表明jwt过期
     *
     * @param token
     * @return
     */
    public Claims resolveTokenBody(String token) throws Exception {
        //Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        SecretKey key = Keys.hmacShaKeyFor(jwtSecret.getBytes());
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
//
//        return Jwts.parser()
//                .setSigningKey(jwtSecret)
//                .parseClaimsJws(token)
//                .getBody();
    }

    /**
     * 验证token是否快过期
     *
     * @return
     */
    public boolean isNearlyExpire(Claims body) {
        Date preExpireTime = new Date(body.getExpiration().getTime()-jwtAutoRefreshInAdvance*1000);
        if (preExpireTime.before(new Date())) {
            return true;
        }
        return false;
    }

    /**
     * 刷新token
     *
     * @param body
     * @return
     */
    public String refreshToken(Claims body, String subject, String role) {
        // 如果没有过期，才能执行刷新
        if (!body.getExpiration().before(new Date())) {
            return createToken(subject, role);
        }
        return null;
    }

    /**
     * 刷新token
     *
     * @param body
     * @return
     */
    public String refreshToken(Claims body, String subject, Map<String,Object> data) {
        // 如果没有过期，才能执行刷新
        if (!body.getExpiration().before(new Date())) {
            return createToken(subject, data);
        }
        return null;
    }


}
